﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using starLiGHT.Collision;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace starLiGHT.Sandbox.Collision
{
    public class HullObject : ICollidable2D
    {
        public event EventHandler Moved;

        #region Member Variables
        private CircleF boundingCircle;
        private RectangleF boundingRectangle;
        private bool worldRectDirty = true;
        private RectangleF worldRect;
        private OrientedRectangleF orientedRectangle;
        private Hull2D hull;
        private Transform2D transform;
        private Vector2 lastPosition;
        private Texture2D texture;
        #endregion

        /// <summary>
        /// Creates a new HullObject.
        /// </summary>
        /// <param name="points">
        /// The positions of the hulls vertices in world space.
        /// </param>
        public HullObject(params Vector2[] points)
            : this(Vector2.Zero, points)
        {
        }

        /// <summary>
        /// Creates a new HullObject.
        /// </summary>
        /// <param name="origin">
        /// The origin of the hull object.
        /// </param>
        /// <param name="points">
        /// The positions of the hulls vertices in world space.
        /// </param>
        public HullObject(Vector2 origin, params Vector2[] points)
        {
            if (points == null)
                throw new ArgumentNullException("points");

            // offset of the first point is the position
            // all vertices of the hull are relative to this position
            // because the hull is in object space
            Vector2 position = points[0];

            // create the local positions
            Vector2[] hullPoints = new Vector2[points.Length];
            for (int i = 0; i < hullPoints.Length; i++)
            {
                hullPoints[i] = points[i] - position;
            }
            hull = new Hull2D(hullPoints);

            boundingRectangle = RectangleF.FromPoints(hullPoints);
            orientedRectangle = new OrientedRectangleF(boundingRectangle);
            boundingCircle = new CircleF(boundingRectangle);

            transform = new Transform2D(position);
            transform.Origin = origin;
            transform.Changed += new EventHandler<EventArgs>(transform_Changed);
        }

        void transform_Changed(object sender, EventArgs e)
        {
            worldRectDirty = true;
            if (Moved != null)
            {
                Moved(sender, e);
            }
        }

        public Vector2 Origin
        {
            get { return this.transform.Origin.HasValue ? this.transform.Origin.Value : Vector2.Zero; }
            set { this.transform.Origin = value; }
        }

        public RectangleF LocalBoundingRectangle
        {
            get { return boundingRectangle; }
        }

        public RectangleF WorldBoundingRectangle
        {
            get
            {
                if (worldRectDirty)
                {
                    worldRect = boundingRectangle;
                    worldRect.Center = Vector2.Transform(boundingRectangle.Center, transform.TransformationMatrix);
                    worldRectDirty = false;
                }

                return worldRect;
            }
        }

        public CircleF BoundingCircle
        {
            get { return boundingCircle; }
        }

        public Transform2D Transform
        {
            get { return transform; }
        }

        public Vector2 Position
        {
            get { return (transform.Position.HasValue ? transform.Position.Value : Vector2.Zero); }
            set
            {
                if ((transform.Position.HasValue ? transform.Position.Value : Vector2.Zero) != value)
                {
                    lastPosition = Position;
                    transform.Position = value;
                }
            }
        }

        // circle cannot rotate
        public float Orientation
        {
            get { return transform.Orientation; }
            set 
            {
                if (transform.Orientation != value)
                {
                    transform.Orientation = value;
                    orientedRectangle.Rotation = transform.Orientation;
                    boundingRectangle = orientedRectangle.ToRectangleF();
                    boundingCircle = new CircleF(boundingRectangle);
                }
            }
        }

        // always the same size for now
        public Vector2 Scale
        {
            get { return (transform.Scale.HasValue ? transform.Scale.Value : Vector2.One); }
        }

        public Texture2D Texture
        {
            get { return texture; }
            set { texture = value; }
        }

        public bool Colliding
        {
            get;
            set;
        }

        public bool Static
        {
            get;
            set;
        }

        public Hull2D Hull
        {
            get { return hull; }
        }

        public Vector2 Velocity
        {
            get;
            set;
        }

        public object Tag
        {
            get;
            set;
        }

        public void LookAt(Vector2 target)
        {
            Vector2 dir = target - Position;
            Orientation = (float)Math.Atan2(dir.Y, dir.X);
        }
    }
}
